package com.foxzzz.osf.store;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Map;

public class LocalFileBufferHolder {
    public static volatile Map<String, FileAndChannel> cacheMap = new HashMap<>();

    public MappedByteBuffer getBuffer(String filePath, long start, long end) throws IOException {
        //Double Check!
        FileAndChannel fileAndChannel = cacheMap.get(filePath);
        if (fileAndChannel == null) {
            synchronized (cacheMap) {
                if (null == cacheMap.get(filePath)) {
                    fileAndChannel = new FileAndChannel(filePath);
                    cacheMap.put(filePath, fileAndChannel);
                    fileAndChannel.open();
                }
            }
        }
        fileAndChannel.updateTimestamp();
        return fileAndChannel.getBuffer(start, end - start);
    }


    public static class FileAndChannel {
        private String path;
        private final static String MODE_RW = "rw";
        private RandomAccessFile raf;
        private FileChannel channel;
        private long lastUseTimestamp;


        public FileAndChannel(String path) {
            this.path = path;
        }

        public void open() throws IOException {
            updateTimestamp();
            close();
            raf = new RandomAccessFile(path, MODE_RW);
            channel = raf.getChannel();
        }

        public void updateTimestamp() {
            lastUseTimestamp = System.currentTimeMillis();
        }

        public MappedByteBuffer getBuffer(long start, long size) throws IOException {
            if (channel == null) {
                throw new RuntimeException("Channel Not Open !");
            }
            return channel.map(FileChannel.MapMode.READ_WRITE, start, size);
        }

        public void close() throws IOException {
            if (channel != null) {
                channel.close();
            }
            if (raf != null) {
                raf.close();
            }
        }
    }

}
